﻿Public Class PodcastManager
  Implements IDisposable

  Private _db As AvianPlayDB = Nothing  ' This is used by the update thread.  Since it's used by a thread, we shouldn't use the main db connection
  Private _dsm As New DeviceSleepManager()
  Private _downloadThread As Threading.Thread = Nothing
  Private _raiseEvents As Boolean = True
  Private _ini As New Ini.File(Settings.INIPodcastsPath)
  Private _interval As Integer = 1
  Private _cancel As Boolean = False
  Private _ignoreUpdateDate As Boolean = False
  Private WithEvents _lit As OpenNETCF.WindowsCE.LargeIntervalTimer = Nothing

#Region " Emulator Debugging Workaround "
  ' The emulator has absolutely terrible timing for scheduled notifications.  I've seen the event timer firing
  ' events as far off as several hours!  This is unnacceptible for testing purposes, so all this extra code
  ' here is to fire off a regular timer instead of the LIT, which uses the notification subsystem.  This code
  ' is only compiled when the project is set to DEBUG, and further only starts the regular timer if the
  ' emulator is detected.
#If CONFIG = "Debug" Then
  Private Declare Function SystemParametersInfo Lib "coredll.dll" (ByVal uiAction As UInteger, ByVal uiParam As UInteger, ByVal pvParam As System.Text.StringBuilder, ByVal fWiniIni As UInteger) As Integer
  Private ReadOnly Property IsEmulator()
    Get
      Dim sb As New System.Text.StringBuilder(128)
      SystemParametersInfo(258, sb.Capacity, sb, 0)
      If sb.ToString = "Microsoft DeviceEmulator" Then
        Return True
      End If
      Return False
    End Get
  End Property
  Private WithEvents _litx As New Timer()
  Private Sub litx_tick(ByVal sender As Object, ByVal e As EventArgs) Handles _litx.Tick
    Me._litx.Enabled = False
    If Me.IsEmulator Then
      Me._litx.Interval = 3600000
      Me._litx.Enabled = True
      Me.StartDownloadThread()
    End If
  End Sub
#End If
#End Region

  Public Event DownloadThreadStatusChanged(ByVal isRunning As Boolean, ByVal isDownloading As Boolean, ByVal bytesDownloaded As Integer, ByVal bytesSize As Integer)
  Public Event WriteErrorOnMainThread(ByVal err As String)
  Public Event FileIsDownloaded(ByVal filePath As String)

  Public Class FeedItem
    Implements IComparable(Of FeedItem)
    Public downloadUrl As String = ""
    Public publishDate As Date = AvianPlayDB.MinimumDateTime
    Public mime As String = ""
    Public need As Boolean = True

    Public Function CompareTo(ByVal other As FeedItem) As Integer Implements System.IComparable(Of FeedItem).CompareTo
      Dim comp As Integer = Me.publishDate.CompareTo(other.publishDate)
      Return 0 - comp ' Do this because we want to sort descending
    End Function
  End Class

  Public Sub New()
    Me._lit = New OpenNETCF.WindowsCE.LargeIntervalTimer()
    Me._lit.OneShot = False
  End Sub

  Public Sub Start()
    Me.Stop()
    Me._lit.Interval = New TimeSpan(0, 1, 0)
    Me._lit.Enabled = True

#If CONFIG = "Debug" Then
    If Me.IsEmulator Then
      Me._lit.Enabled = False
      Me._litx.Interval = 10000
      Me._litx.Enabled = True
    End If
#End If

    '    RaiseEvent WriteErrorOnMainThread("@@@ PodCastManager Started") ' TODO: Remove this
  End Sub

  Public Sub [Stop]()
    Me._lit.Enabled = False

#If CONFIG = "Debug" Then
    Me._litx.Enabled = False
#End If

    Me.KillDownloadThread()

    '    RaiseEvent WriteErrorOnMainThread("@@@ PodCastManager Stopped") ' TODO: Remove this
  End Sub

  Public Property IntervalHours() As Integer
    Get
      Return Me._interval
    End Get
    Set(ByVal value As Integer)
      If value > 0 Then
        Dim lastenabled As Boolean = Me._lit.Enabled
        Me._lit.Enabled = False
        Me._interval = value
        Me._lit.Interval = New TimeSpan(Me._interval, 0, 0)
        Me._lit.Enabled = lastenabled
      Else
        Me.Stop()
      End If
    End Set
  End Property

  Public Property RaiseEvents() As Boolean
    Get
      Return Me._raiseEvents
    End Get
    Set(ByVal value As Boolean)
      Me._raiseEvents = value
    End Set
  End Property

  Public Sub KillDownloadThread()
    If Me._downloadThread IsNot Nothing Then
      Me._downloadThread.Abort()
    End If
  End Sub

  Public Sub StartDownloadThread(Optional ByVal ignoreUpdateDate As Boolean = False)
    If Me._downloadThread Is Nothing Then
      Me._cancel = False
      Me._ignoreUpdateDate = ignoreUpdateDate

      SyncLock MainThreadPool
        Me._downloadThread = New Threading.Thread(AddressOf DownloadThread)
        Me._downloadThread.Name = "DownloadThread"
        Me._downloadThread.Priority = Threading.ThreadPriority.Lowest
        Me._downloadThread.Start()
        Main.MainThreadPool.Add(Me._downloadThread)
      End SyncLock
    End If
  End Sub

  Public Sub CancelDownloadThread()
    If Me._downloadThread IsNot Nothing Then
      Me._cancel = True
    End If
  End Sub

  Private Sub DownloadThread()
    Try
      '      RaiseEvent WriteErrorOnMainThread("@@@ Podcast Manager: DownloadThread begins!") ' TODO: Remove this

      Dim ignoreUpdateDate As Boolean = Me._ignoreUpdateDate

      Me._dsm.StartPreventDeviceSleep("AvianPlay_PodcastManager_")

      ' Tell host that we are trying to update podcasts
      If Me._raiseEvents Then RaiseEvent DownloadThreadStatusChanged(True, False, 0, 0)

      Using db As New AvianPlayDB
        ' Fetch all existing podcast files managed by Avian Play's PCM
        Dim currentFiles As List(Of AvianPlayDB.PodcastSubscriptionTable) = db.GetAllSubscriptionPodcastFiles

        ' Look at all files to see if they all still exist in the file system.
        Dim missingFiles As New List(Of AvianPlayDB.PodcastSubscriptionTable)
        For Each pst As AvianPlayDB.PodcastSubscriptionTable In currentFiles
          If Not IO.File.Exists(pst.FilePath) Then
            missingFiles.Add(pst)
          End If
        Next

        ' Remove the missing files from the existing files table, so that they get redownlaoded, if needed
        For Each pst In missingFiles
          currentFiles.Remove(pst)
          db.RemoveSubscriptionPodcastFile(pst.Key)
        Next

        ' Do we have a previously incompleted download?
        Dim tmpfn As String = Me.GetTempFileFilename
        If tmpfn IsNot Nothing Then
          tmpfn = tmpfn.Trim

          ' Check to see if the previous temp file is recorded, and if so, is it in our files table, because if it is, we want to ignore it
          For Each pst As AvianPlayDB.PodcastSubscriptionTable In currentFiles
            If String.Compare(pst.FilePath.Trim, tmpfn, True) = 0 Then
              tmpfn = Nothing
              Exit For
            End If
          Next
        End If

        ' Remove the temporary file, if it previously existed
        If tmpfn IsNot Nothing Then
          Try
            IO.File.Delete(tmpfn)
          Catch ex As Exception
            If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadThread :: Unable to delete temporary file :: " & ex.ToString)
          End Try
        End If

        ' For i As Integer = 0 To subscriptions - 1
        For Each curSection As Ini.Section In Me._ini.Sections
          ' Do we need to cancel the process?
          If Me._cancel Then Exit Sub

          ' Does the section still exist?
          If curSection IsNot Nothing Then
            If String.Compare(Left(curSection.Name, 12), "Subscription", True) = 0 Then
              Dim subscrip As Integer? = curSection.IntegerValue("Index")
              If subscrip IsNot Nothing Then
                ' How many podcasts do we keep?
                Dim history As Integer = curSection.IntegerValueNoNull("History")

                ' The title of the subscription
                Dim title As String = curSection.StringValueNoNull("Title", "Podcast " & subscrip.ToString)

                ' Get only the subscriptions for this list; removes from the main list (we clean those up at the bottom)
                Dim curSub As List(Of AvianPlayDB.PodcastSubscriptionTable) = Me.SubscriptionFilter(currentFiles, subscrip)

                ' Check if we need to perform an update on this subscription
                If ignoreUpdateDate OrElse (Date.Now.Subtract(New Date(curSection.LongValueNoNull("LastUpdate"))).TotalHours > CDbl(curSection.IntegerValueNoNull("Interval"))) Then
                  If Me.DownloadPodcasts(db, title, subscrip, curSection.StringValueNoNull("URL"), curSection.StringValueNoNull("Location", "/"), history, curSub) Then
                    ' If the download didn't crash, clean up the history of this subscription
                    Me.SubscriptionHistoryMaintenance(db, curSub, history)

                    ' Update the last update interval only when update is successful
                    curSection.LongValue("LastUpdate") = Date.Now.Ticks
                  End If

                  ' Make sure the values are set in the ini file and are not relying just on default values
                  curSection.IntegerValue("Interval") = curSection.IntegerValueNoNull("Interval")
                  curSection.IntegerValue("History") = curSection.IntegerValueNoNull("History")
                End If
              Else
                ' This is an invalid section
                If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadThread :: Invalid Section Index in " & curSection.Name)
              End If
            End If
          End If
        Next

        ' For all other leftover files, remove them and their entry in the DB, as those subscriptions don't exist any more
        For Each pst As AvianPlayDB.PodcastSubscriptionTable In currentFiles
          Me.PurgePodcastFile(db, pst)
        Next
      End Using
    Catch ex As Threading.ThreadAbortException
      ' Safe to ignore
    Catch ex As Exception
      If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadThread :: Uncaught exception :: " & ex.ToString)
    Finally
      Try
        If Not Me._cancel Then
          ' don't save the INI if we cancelled, so that the next retry interval will pick up any file that didn't complete.
          Me._ini.Save(Settings.INIPodcastsPath)
        End If
      Catch ex As Threading.ThreadAbortException
        ' Also safe to ignore
      Catch ex As Exception
        If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadThread :: Unable to save podcasts.ini :: " & ex.ToString)
      End Try
      SyncLock MainThreadPool
        Main.MainThreadPool.Remove(Me._downloadThread)
      End SyncLock
      Me._downloadThread = Nothing
      If Me._raiseEvents Then RaiseEvent DownloadThreadStatusChanged(False, False, 0, 0)
      Me._dsm.StopPreventDeviceSleep()
    End Try
  End Sub

  Private Function SubscriptionFilter(ByRef fileList As List(Of AvianPlayDB.PodcastSubscriptionTable), ByVal subscription As Integer) As List(Of AvianPlayDB.PodcastSubscriptionTable)
    Dim curSub As New List(Of AvianPlayDB.PodcastSubscriptionTable)

    ' Fetch only the files related to this subscription
    For Each pst In fileList
      If pst.Subscription = subscription Then
        curSub.Add(pst)
      End If
    Next

    ' Remove from main list (passed by ref, so it removes from caller function
    For Each pst In curSub
      fileList.Remove(pst)
    Next

    ' Sort by date descending (default sorter for PST sorts descending)
    curSub.Sort()

    ' Return what we got
    Return curSub
  End Function

  Private Sub SubscriptionHistoryMaintenance(ByVal db As AvianPlayDB, ByRef curlist As List(Of AvianPlayDB.PodcastSubscriptionTable), ByVal historyLength As Integer)
    If historyLength < 1 Then
      historyLength = 1 ' Minimum history length is one!
    End If

    ' Sort by date descending (default sorter for PST sorts descending)
    curlist.Sort()

    ' Now purge any old files
    For i As Integer = 0 To curlist.Count - 1
      If i >= historyLength Then
        Me.PurgePodcastFile(db, curlist(i))
      End If
    Next
  End Sub

  Private Sub PurgePodcastFile(ByVal db As AvianPlayDB, ByVal pst As AvianPlayDB.PodcastSubscriptionTable)
    If IO.File.Exists(pst.FilePath) Then
      Try
        IO.File.Delete(pst.FilePath)
        db.RemoveSubscriptionPodcastFile(pst.Key)
      Catch ex As Threading.ThreadAbortException
        Throw
      Catch ex As System.IO.IOException
        ' File is in use.  We don't want to remove the file from DB
      Catch ex As System.UnauthorizedAccessException
        ' Don't have access for some reason.  We don't want to remove the file from DB
      Catch ex As Exception
        ' Some other error occurred.  Don't need to notify the user, but we should log it
        If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadThread :: Unable to delete file :: " & ex.ToString)
      End Try
    Else ' File doesn't exist, so just remove it from db
      db.RemoveSubscriptionPodcastFile(pst.Key)
    End If
  End Sub

  Private Function DownloadPodcasts(ByVal db As AvianPlayDB, ByVal title As String, ByVal subscrip As Integer, ByVal url As String, ByVal location As String, ByVal history As Integer, ByVal curFiles As List(Of AvianPlayDB.PodcastSubscriptionTable))
    '    RaiseEvent WriteErrorOnMainThread("@@@ PodCastManager in DownloadPodcasts") ' TODO: Remove this

    If IO.Directory.Exists(location) Then
      Try
        Dim result As Boolean = True
        Dim feedList As New List(Of FeedItem)
        Dim rssURL As New Uri(url)
        Dim req As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(url)
        Using resp As System.Net.HttpWebResponse = req.GetResponse
          Using reader As New Xml.XmlTextReader(resp.GetResponseStream)
            'reader.MoveToContent()

            While reader.Read
              If Me._cancel Then Return False

              If reader.LocalName.ToLower = "channel" Then
                Dim item As FeedItem = Nothing

                ' This is RSS
                While reader.Read
                  If reader.NodeType = Xml.XmlNodeType.Element Then
                    If reader.LocalName.ToLower = "item" Then
                      item = New FeedItem
                    ElseIf reader.LocalName.ToLower = "pubdate" AndAlso item IsNot Nothing Then
                      Dim dStr As String = String.Empty
                      Try
                        dStr = reader.ReadString
                        item.publishDate = Date.Parse(dStr)
                      Catch ex As Threading.ThreadAbortException
                        Throw
                      Catch ex As Exception
                        If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadPodcasts :: Unable to parse PublishDate [RSS] on feed " & subscrip.ToString & " :: " & url & " :: " & dStr)
                      End Try
                    ElseIf reader.LocalName.ToLower = "enclosure" AndAlso item IsNot Nothing Then
                      item.downloadUrl = reader.GetAttribute("url").Trim
                      item.mime = reader.GetAttribute("type").Trim
                    End If
                  ElseIf reader.NodeType = Xml.XmlNodeType.EndElement AndAlso reader.LocalName.ToLower = "item" Then
                    If item.downloadUrl <> "" Then
                      feedList.Add(item)
                      item = Nothing
                    End If
                  End If
                End While

                Exit While ' Exit the outer while
              ElseIf reader.LocalName.ToLower = "feed" Then
                Dim item As FeedItem = Nothing

                ' This is ATOM
                While reader.Read
                  If reader.NodeType = Xml.XmlNodeType.Element Then
                    If reader.LocalName.ToLower = "entry" Then
                      item = New FeedItem
                    ElseIf reader.LocalName.ToLower = "published" AndAlso item IsNot Nothing Then
                      Dim dStr As String = String.Empty
                      Try
                        dStr = reader.ReadString
                        item.publishDate = Date.Parse(dStr)
                      Catch ex As Threading.ThreadAbortException
                        Throw
                      Catch ex As Exception
                        If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadPodcasts :: Unable to parse PublishDate [ATOM] on feed " & subscrip.ToString & " :: " & url & " :: " & dStr)
                      End Try
                    ElseIf reader.LocalName.ToLower = "link" AndAlso reader.GetAttribute("rel") IsNot Nothing AndAlso reader.GetAttribute("rel").ToLower = "enclosure" AndAlso item IsNot Nothing Then
                      item.downloadUrl = reader.GetAttribute("href").Trim
                      item.mime = reader.GetAttribute("type").Trim
                    End If
                  ElseIf reader.NodeType = Xml.XmlNodeType.EndElement AndAlso reader.LocalName.ToLower = "entry" Then
                    If item.downloadUrl <> "" Then
                      feedList.Add(item)
                      item = Nothing
                    End If
                  End If
                End While

                Exit While ' Exit the outer while
              End If
            End While

            ' Check to see if we have missing publish dates and to set the order correctly (presumably we are adding the streams newest first)
            Dim secCount As Integer = 0 ' Used for augmenting the time slightly to preserve order
            Dim lastdate As Date = Date.Now
            For i As Integer = 0 To feedList.Count - 1
              If feedList(i).publishDate <= AvianPlayDB.MinimumDateTime Then
                feedList(i).publishDate = lastdate.AddSeconds(secCount) ' By adding a few seconds, we ensure that the order is preserved when sorted by publish date
                secCount += 1
              Else
                lastdate = feedList(i).publishDate ' We want to make sure an entry toward the bottom of the list doesn't jump to the top
                secCount = 0
              End If
            Next

            ' Sort by publish date descending
            feedList.Sort()

            ' Remove ones past the history length
            For i As Integer = 0 To feedList.Count - 1
              If i >= history Then
                feedList(i).need = False
              End If
            Next

            ' Remove ones we already have
            For Each item As FeedItem In feedList
              For Each pst As AvianPlayDB.PodcastSubscriptionTable In curFiles
                If item.need AndAlso String.Compare(item.downloadUrl.Trim, pst.DownloadURL.Trim, True) = 0 Then
                  item.need = False
                  Exit For
                End If
              Next
            Next

            ' Now download each file that needs to be downloaded
            For i As Integer = 0 To feedList.Count - 1
              If Me._cancel Then Return False

              If feedList(i).need Then
                ' Is this a valid MIME type?
                Dim ext As String = Settings.GetAudioExtensionForMimeType(feedList(i).mime)
                If ext IsNot Nothing Then
                  Dim fp As String = GetRandomFileName(location, Left(title, 12) & "_" & feedList(i).publishDate.ToString("yyMMddHHmm") & "_", 5, 1, ext)
                  If fp.Length < 260 Then
                    If Me.SaveDownload(fp, feedList(i).downloadUrl) Then
                      Try
                        Dim pst As New AvianPlayDB.PodcastSubscriptionTable
                        pst.FilePath = fp
                        pst.Subscription = subscrip
                        pst.DownloadURL = feedList(i).downloadUrl
                        pst.PublishTime = feedList(i).publishDate
                        pst.DownloadTime = Date.Now
                        db.InsertSubscriptionPodcastFile(pst)
                        curFiles.Add(pst)
                      Catch ex As Exception
                        Try
                          IO.File.Delete(Me.GetTempFileFilename)
                          Me.RemoveTempFile()
                        Catch
                        End Try
                        Throw ex
                      End Try
                    Else
                      If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadPodcasts :: Download failed: " & feedList(i).downloadUrl)
                      result = False
                    End If
                  Else
                    If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadPodcasts :: Unable to save podcast file; path is too long: " & fp)
                    result = False
                  End If
                End If
              End If
            Next
          End Using
        End Using

        Return result
      Catch ex As Threading.ThreadAbortException
        Throw
      Catch ex As Exception
        If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadPodcasts :: " & ex.ToString)
        Return False ' I'm not entirely sure why, but it seems that an exception thrown inside the 'using' statements may return control back to the return true?  Anyway, I'm returning inside the exception to make sure it doesn't do this.
      Finally
        ' Set download status back to just "updating"
        If Me._raiseEvents Then RaiseEvent DownloadThreadStatusChanged(True, False, 0, 0)
      End Try
    Else
      If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.DownloadPodcasts :: Folder does not exist")
    End If
    Return False
  End Function

  Private Function SaveDownload(ByVal filename As String, ByVal url As String) As Boolean
    Dim isComplete As Boolean = False
    Try
      Dim totalBytesRead As Integer = 0
      Dim totalBytesSize As Integer = 0

      ' Create the local download file
      Me.SetTempFilename(filename)

      '      RaiseEvent WriteErrorOnMainThread("@@@ PodCastManager !!!SAVEDOWNLOAD!!!") ' TODO: Remove this

      Using outfile As New IO.FileStream(filename, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.Read)
        Dim req As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(url)
        Using resp As System.Net.HttpWebResponse = req.GetResponse
          Dim rs As IO.Stream = resp.GetResponseStream
          totalBytesSize = CInt(resp.ContentLength)
          If Me._raiseEvents Then RaiseEvent DownloadThreadStatusChanged(True, True, 0, totalBytesSize)

          Dim b(32767) As Byte
          Dim bytesRead As Integer = rs.Read(b, 0, b.Length)
          While bytesRead > 0 AndAlso Not Me._cancel
            outfile.Write(b, 0, bytesRead)
            bytesRead = rs.Read(b, 0, b.Length)
            totalBytesRead += bytesRead
            If Me._raiseEvents Then RaiseEvent DownloadThreadStatusChanged(True, True, totalBytesRead, totalBytesSize)
          End While

          ' Show that the file is done without error
          If Me._raiseEvents Then RaiseEvent DownloadThreadStatusChanged(True, True, totalBytesSize, totalBytesSize)

          ' Flush and close the writer
          rs.Flush()
          rs.Close()
        End Using
      End Using

      If Not Me._cancel Then
        isComplete = True
        If Me.RaiseEvents Then RaiseEvent FileIsDownloaded(filename)
      End If
    Catch ex As Threading.ThreadAbortException
      Throw ' Pass it on...
    Catch ex As Exception
      If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.SaveDownload :: " & ex.ToString)
    Finally
      If Not isComplete Then
        Try
          ' Download didn't complete, so let's (try to) nuke the partial file
          IO.File.Delete(filename)
        Catch
        End Try
      End If

      ' Set the status back to 'updating'
      If Me._raiseEvents Then RaiseEvent DownloadThreadStatusChanged(True, False, 0, 0)
    End Try
    Return isComplete
  End Function


  Private Sub Lit_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles _lit.Tick
    '    RaiseEvent WriteErrorOnMainThread("@@@ Podcast Manager: Tick!") ' TODO: Remove this

    If Me._lit.Interval.TotalMinutes <= 1 Then
      Me._lit.Enabled = False
      Me._lit.Interval = New TimeSpan(Me._interval, 0, 0)
      Me._lit.Enabled = True
      '      RaiseEvent WriteErrorOnMainThread("@@@ Podcast Manager: Set timer to " & Me._interval & " hour interval!") ' TODO: Remove this
    End If

    Me.StartDownloadThread()
  End Sub

  Public ReadOnly Property IsUpdating() As Boolean
    Get
      Return (Me._downloadThread IsNot Nothing)
    End Get
  End Property

  Public Function GetTempFileFilename() As String
    Try
      If IO.File.Exists(Settings.PodcastDownloadTemporaryPath) Then
        Dim dltmp As New Ini.File(Settings.PodcastDownloadTemporaryPath)
        Dim tempfn As String = dltmp.SectionNoNull("PodcastTempFile").StringValue("Path")
        Dim temphsh As String = dltmp.SectionNoNull("PodcastTempFile").StringValue("Hash")
        If tempfn IsNot Nothing AndAlso tempfn.Trim.Length > 0 AndAlso temphsh IsNot Nothing AndAlso temphsh.Trim.Length > 0 AndAlso IO.File.Exists(tempfn) AndAlso temphsh = Me.GetMD5String(tempfn) Then
          Return tempfn
        Else
          Me.RemoveTempFile()
        End If
      End If
    Catch ex As Exception
      If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.GetTempFileFilename :: " & ex.ToString)
    End Try

    Return Nothing
  End Function

  Public Sub SetTempFilename(ByVal path As String)
    Try
      Dim dltmp As New Ini.File()
      dltmp.AddSection("PodcastTempFile")
      dltmp.Section("PodcastTempFile").StringValue("Path") = path
      dltmp.Section("PodcastTempFile").StringValue("Hash") = Me.GetMD5String(path)
      dltmp.Save(Settings.PodcastDownloadTemporaryPath)
    Catch ex As Exception
      If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.SetTempFilename :: " & ex.ToString)
    End Try
  End Sub

  Public Sub RemoveTempFile()
    If IO.File.Exists(Settings.PodcastDownloadTemporaryPath) Then
      Try
        IO.File.Delete(Settings.PodcastDownloadTemporaryPath)
      Catch ex As Exception
        If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.RemoveTempFile :: " & ex.ToString)
      End Try
    End If
  End Sub

  Private Function GetMD5String(ByVal str As String) As String
    Try
      Using md5 As New System.Security.Cryptography.MD5CryptoServiceProvider
        Dim enc As New System.Text.UTF8Encoding()
        Dim b() As Byte = enc.GetBytes(str)
        Dim mb() As Byte = md5.ComputeHash(b)
        Dim b64s As String = Convert.ToBase64String(mb)
        Return b64s
      End Using
    Catch ex As Exception
      If Me._raiseEvents Then RaiseEvent WriteErrorOnMainThread("PodcastManager.GetMD5String :: " & ex.ToString)
      Return String.Empty
    End Try
  End Function

#Region " IDisposable Support "
  Private disposedValue As Boolean = False    ' To detect redundant calls

  ' IDisposable
  Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposedValue Then
      If disposing Then
        Me.RaiseEvents = False
        Me.Stop()
      End If
    End If
    Me.disposedValue = True
  End Sub

  ' This code added by Visual Basic to correctly implement the disposable pattern.
  Public Sub Dispose() Implements IDisposable.Dispose
    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
#End Region

End Class
